namespace SimpleWebServices.Web.Mvc
{
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Threading;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using HtmlAgilityPack;
    using Moq;
    using Newtonsoft.Json;
    using SimpleWebServices;
    using SimpleWebServices.Models;
    using SimpleWebServices.Web.Routing;
    using Xunit;

    public sealed class SiteControllerFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<SiteController>()
                .DerivesFrom<ResourceController>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .IsDecoratedWith<InternalServerErrorAttribute>()
                .Allow("GET, HEAD, OPTIONS")
                .IsDecoratedWith<CacheControlAttribute>()
                .IsDecoratedWith<ContentLanguageAttribute>()
                .IsDecoratedWith<ContentLocationAttribute>()
                .IsDecoratedWith<ContentMD5Attribute>()
                .Resource("site")
                .Implements<IRegisterRoutes>()
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new SiteController());
        }

        [Fact]
        public void op_Register_RouteCollection()
        {
            RouteCollection routes = new RouteCollection();

            (new SiteController() as IRegisterRoutes).Register(routes);

            Assert.Equal<int>(14, routes.Count);

            int i = 0;
            Assert.Equal<string>("site.{language}.html", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.html", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.json", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.json", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.txt", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.txt", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.xhtml", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.xhtml", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.xml", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}.xml", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}", (routes[i++] as Route).Url);
            Assert.Equal<string>("site.{language}", (routes[i++] as Route).Url);
            Assert.Equal<string>("site", (routes[i++] as Route).Url);
            Assert.Equal<string>("site", (routes[i++] as Route).Url);
        }

        [Fact]
        public void op_HtmlRepresentation_CultureInfo()
        {
            CultureInfo culture = Thread.CurrentThread.CurrentUICulture;

            try
            {
                string host = "example.com";
                string machine = "ABC123";

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<NameValueCollection>(x => x.Request.Headers).Returns(new NameValueCollection { { "Host", host } }).Verifiable();
                mock.SetupGet<string>(x => x.Server.MachineName).Returns(machine).Verifiable();
                HttpContextFactory.Mock = mock.Object;

                CultureInfo language = new CultureInfo("en");
                ActionResult obj = new SiteController().HtmlRepresentation(language);
                Assert.Equal<CultureInfo>(language, Thread.CurrentThread.CurrentUICulture);

                Assert.Equal<string>("text/html", (obj as ContentResult).ContentType);

                HtmlDocument html = new HtmlDocument();
                html.LoadHtml((obj as ContentResult).Content);

                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/title[text()='Site Information'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@http-equiv='Content-Type'][@content='text/html'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@name='DC.format'][@scheme='IMT'][@content='text/html'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@name='DC.type'][@scheme='DCMIType'][@content='Text'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@content='NOFOLLOW,NOINDEX'][@name='robots'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/body/h1[text()='Site Information'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/body/dl[@id='server']/dd[@id='host'][text()='" + host + "'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/body/dl[@id='server']/dd[@id='machine'][text()='" + machine + "'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("0!=count(/html/body/ul[@id='assemblies']/li)"));

                mock.VerifyAll();
            }
            finally
            {
                Thread.CurrentThread.CurrentUICulture = culture;

                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_JsonRepresentation_CultureInfo()
        {
            CultureInfo culture = Thread.CurrentThread.CurrentUICulture;

            try
            {
                string host = "example.com";
                string machine = "ABC123";

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<NameValueCollection>(x => x.Request.Headers).Returns(new NameValueCollection { { "Host", host } }).Verifiable();
                mock.SetupGet<string>(x => x.Server.MachineName).Returns(machine).Verifiable();
                HttpContextFactory.Mock = mock.Object;

                CultureInfo language = new CultureInfo("en");
                ActionResult obj = new SiteController().JsonRepresentation(language);
                Assert.Equal<CultureInfo>(language, Thread.CurrentThread.CurrentUICulture);

                Assert.Equal<string>("application/vnd.simplewebservices-site+json", (obj as JsonSerializationResult).ContentType);

                Site model = JsonConvert.DeserializeObject<Site>((obj as JsonSerializationResult).Content);

                Assert.NotEmpty(model.Assemblies);
                Assert.Equal<string>(host, model.Host);
                Assert.Equal<string>(machine, model.Machine);

                mock.VerifyAll();
            }
            finally
            {
                Thread.CurrentThread.CurrentUICulture = culture;

                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_TextRepresentation_CultureInfo()
        {
            CultureInfo culture = Thread.CurrentThread.CurrentUICulture;

            try
            {
                string host = "example.com";
                string machine = "ABC123";

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<NameValueCollection>(x => x.Request.Headers).Returns(new NameValueCollection { { "Host", host } }).Verifiable();
                mock.SetupGet<string>(x => x.Server.MachineName).Returns(machine).Verifiable();
                HttpContextFactory.Mock = mock.Object;

                CultureInfo language = new CultureInfo("en");
                ActionResult obj = new SiteController().TextRepresentation(language);
                Assert.Equal<CultureInfo>(language, Thread.CurrentThread.CurrentUICulture);

                Assert.Equal<string>("text/plain", (obj as TextResult).ContentType);
                Assert.True((obj as TextResult).Content.Contains("[Server]"));
                Assert.True((obj as TextResult).Content.Contains("Host: example.com"));
                Assert.True((obj as TextResult).Content.Contains("Machine: ABC123"));
                Assert.True((obj as TextResult).Content.Contains("[Assemblies]"));
                Assert.True((obj as TextResult).Content.Contains("Assembly: "));

                mock.VerifyAll();
            }
            finally
            {
                Thread.CurrentThread.CurrentUICulture = culture;

                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_XhtmlRepresentation_CultureInfo()
        {
            CultureInfo culture = Thread.CurrentThread.CurrentUICulture;

            try
            {
                string host = "example.com";
                string machine = "ABC123";

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<NameValueCollection>(x => x.Request.Headers).Returns(new NameValueCollection { { "Host", host } }).Verifiable();
                mock.SetupGet<string>(x => x.Server.MachineName).Returns(machine).Verifiable();
                HttpContextFactory.Mock = mock.Object;

                CultureInfo language = new CultureInfo("en");
                ActionResult obj = new SiteController().XhtmlRepresentation(language);
                Assert.Equal<CultureInfo>(language, Thread.CurrentThread.CurrentUICulture);

                Assert.Equal<string>("application/xhtml+xml", (obj as ContentResult).ContentType);

                HtmlDocument html = new HtmlDocument();
                html.LoadHtml((obj as ContentResult).Content);

                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/title[text()='Site Information'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@http-equiv='Content-Type'][@content='application/xhtml+xml'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@name='DC.format'][@scheme='IMT'][@content='application/xhtml+xml'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@name='DC.type'][@scheme='DCMIType'][@content='Text'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/head/meta[@content='NOFOLLOW,NOINDEX'][@name='robots'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/body/h1[text()='Site Information'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/body/dl[@id='server']/dd[@id='host'][text()='" + host + "'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("1=count(/html/body/dl[@id='server']/dd[@id='machine'][text()='" + machine + "'])"));
                Assert.True((bool)html.CreateNavigator().Evaluate("0!=count(/html/body/ul[@id='assemblies']/li)"));

                mock.VerifyAll();
            }
            finally
            {
                Thread.CurrentThread.CurrentUICulture = culture;

                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_XmlRepresentation_CultureInfo()
        {
            CultureInfo culture = Thread.CurrentThread.CurrentUICulture;

            try
            {
                string host = "example.com";
                string machine = "ABC123";

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<NameValueCollection>(x => x.Request.Headers).Returns(new NameValueCollection { { "Host", host } }).Verifiable();
                mock.SetupGet<string>(x => x.Server.MachineName).Returns(machine).Verifiable();
                HttpContextFactory.Mock = mock.Object;

                CultureInfo language = new CultureInfo("en");
                ActionResult obj = new SiteController().XmlRepresentation(language);
                Assert.Equal<CultureInfo>(language, Thread.CurrentThread.CurrentUICulture);

                Assert.Equal<string>("application/vnd.simplewebservices-site+xml", (obj as XmlSerializationResult).ContentType);

                Site model = (obj as XmlSerializationResult).Content.Deserialize<Site>();

                Assert.NotEmpty(model.Assemblies);
                Assert.Equal<string>(host, model.Host);
                Assert.Equal<string>(machine, model.Machine);

                mock.VerifyAll();
            }
            finally
            {
                Thread.CurrentThread.CurrentUICulture = culture;

                HttpContextFactory.Reset();
            }
        }
    }
}